package pub.elephants.socket;

import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import pub.elephants.net.NetConnectionEnum;
import pub.elephants.net.body.ElephantsRequest;
import pub.elephants.net.body.ElephantsResponse;
import pub.elephants.net.client.ElephantsClient;
import pub.elephants.serializable.ElephantsSerializable;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.UUID;

public class NetClientProxy implements FactoryBean<Object>, InitializingBean {
    private String serverAddress;
    private NetConnectionEnum netcom = NetConnectionEnum.NETTY;
    private ElephantsSerializable serializer = ElephantsSerializable.SerializableTypeEmum.HESSIAN.serializer;
    private Class<?> iface;
    private long timeoutMillis = 5000;

    public NetClientProxy() {
    }

    public NetClientProxy(String serverAddress, NetConnectionEnum netcom, ElephantsSerializable serializer, Class<?> iface, long timeoutMillis) {
        this.serverAddress = serverAddress;
//        this.netcom = netcom;
//        this.serializer = serializer;
        this.iface = iface;
//        this.timeoutMillis = timeoutMillis;
        try {
            this.afterPropertiesSet();
        } catch (Exception e) {
        }
    }

    public void setServerAddress(String serverAddress) {
        this.serverAddress = serverAddress;
    }

    public void setNetcom(NetConnectionEnum netcom) {
        this.netcom = netcom;
    }

    public void setSerializer(ElephantsSerializable serializer) {
        this.serializer = serializer;
    }

    public void setIface(Class<?> iface) {
        this.iface = iface;
    }

    public void setTimeoutMillis(long timeoutMillis) {
        this.timeoutMillis = timeoutMillis;
    }


    //==========================初始化远程服务=====================================//
    @Override
    public Object getObject() throws Exception {
      return   Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[]{iface}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                ElephantsRequest request = new ElephantsRequest();
                request.setCreateCurrentTimeMillis(System.currentTimeMillis());
                request.setClassName(method.getDeclaringClass().getName());
                request.setMethodName(method.getName());
                request.setParamTypes(method.getParameterTypes());
                request.setParamValues(args);
                request.setRequestId(UUID.randomUUID().toString());
                ElephantsResponse response = client.send(request);
                if (response == null) {
                    throw new Exception(" netty response not found.");
                }
                if (response.isSuccess()) {
                    throw response.getError();
                } else {
                    return response.getResult();
                }
            }
        });

    }

    @Override
    public Class<?> getObjectType() {
        return iface;
    }

    @Override
    public boolean isSingleton() {
        return false;
    }


    // ---------------------- init client, operate ----------------------
    ElephantsClient client = null;

    @Override
    public void afterPropertiesSet() throws Exception {
        client = netcom.clientClass.newInstance();
        client.init(serverAddress, serializer, timeoutMillis);
    }

}
